﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace _15Puzzle
{
    public class Board
    {
        private readonly Texture2D texture;
        private readonly SpriteFont font;
        private readonly List<Piece> pieces;
        private readonly int size;
        private readonly int pieceSize;
        public enum Size
        {
            Small = 3,
            Normal = 4,
            Large = 8,
            Extreme = 16
        }

        public Board(Texture2D texture, SpriteFont font, Size size)
        {
            this.texture = texture;
            this.font = font;
            if (Enum.IsDefined(typeof(Size), size))
                this.size = (int)size;
            else this.size = (int)Size.Normal;
            switch (size)
            {
                case Size.Small:
                    {
                        pieceSize = 133;
                        break;
                    }
                case Size.Normal: 
                    {
                        pieceSize = 100;
                        break;
                    }
                case Size.Large:
                    {
                        pieceSize = 50;
                        break;
                    }
                case Size.Extreme:
                    {
                        pieceSize = 25;
                        break;
                    }
            }
            pieces = LoadPieces();
        }

        protected List<Piece> LoadPieces()
        {
            var piecesCount = (size*size) - 1;
            var newPieces = new List<Piece>(piecesCount);
            for (var i = 1; i <= piecesCount; i++)
                newPieces.Add(new Piece(i));
            newPieces = Randomize(newPieces);
            return newPieces;
        }

        private static List<Piece> Randomize(List<Piece> list)
        {
            var randomList = new List<Piece>();
            if (list.Count == 0)
                return randomList;

            var r = new Random();
            while (list.Count > 0)
            {
                var randomIndex = r.Next(0, list.Count);   //Choose a random object in the list
                randomList.Add(list[randomIndex]);         //add it to the new, random list<
                list.RemoveAt(randomIndex);                //remove to avoid duplicates
            }

            //clean up
            list.Clear();
            list = null;
            r = null;

            return randomList;
        }

        public void Draw(SpriteBatch batch)
        {
            var destRect = new Rectangle();
            var srcRect = new Rectangle();
            if (texture == null) return;
            var n = 0;
            foreach (var piece in pieces)
            {
                if (piece == null) continue;
                //Sprite destination area
                var x = (n%size)*pieceSize;
                var y = (n/size)*pieceSize;
                destRect.X = x;
                destRect.Y = y;
                destRect.Width = pieceSize;
                destRect.Height = pieceSize;
                //Size of the texture
                var texWidth = (int) Math.Floor(texture.Width/(float) size);
                var texHeight = (int) Math.Floor(texture.Height/(float) size);
                //Sets the sprite source area from the texture, dependant on the number
                srcRect.X = (piece.Number%size)*texWidth;
                srcRect.Y = (piece.Number/size)*texHeight;
                srcRect.Width = texWidth;
                srcRect.Height = texHeight;
                //Draw sprite
                batch.Draw(texture, destRect, srcRect, Color.White);

                //Calc font scale
                var scale = pieceSize / 100f;
                //Align number to center
                var number = piece.Number.ToString();
                var numberSize = font.MeasureString(number);
                var fontOrigin = new Vector2(-(pieceSize - numberSize.X*scale)/(2*scale), -(pieceSize - numberSize.Y*scale)/(2*scale));

                //Draw number
                batch.DrawString(font, number, new Vector2(x, y), Color.DarkBlue,
                    0f, fontOrigin, scale, SpriteEffects.None, 0f);
                n++;
            }
        }
    }
}
